package com.qys.livesMall.anchor.controller.sys;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qys.livesMall.anchor.business.AnchorLivesBusiness;
import com.qys.livesMall.anchor.constants.RedisConstant;
import com.qys.livesMall.anchor.controller.LiveStreamUtils;
import com.qys.livesMall.anchor.model.dto.lives.sys.CreatePullFlowDTO;
import com.qys.livesMall.anchor.model.dto.lives.sys.QueryLiveRoomDTO;
import com.qys.livesMall.anchor.model.dto.lives.sys.SendMessageDTO;
import com.qys.livesMall.anchor.model.dto.lives.sys.UpdateLiveRooDTO;
import com.qys.livesMall.anchor.model.entity.AnchorLivesRoom;
import com.qys.livesMall.anchor.model.entity.AnchorLivesSession;
import com.qys.livesMall.anchor.model.entity.AnchorSellTask;
import com.qys.livesMall.anchor.model.entity.H2Anchor;
import com.qys.livesMall.anchor.model.vo.lives.sys.SysLiveRoomVO;
import com.qys.livesMall.anchor.service.AnchorLivesRoomService;
import com.qys.livesMall.anchor.service.AnchorLivesSessionService;
import com.qys.livesMall.anchor.service.AnchorSellTaskService;
import com.qys.livesMall.anchor.service.H2AnchorService;
import com.qys.livesMall.app.user.constants.TencentCloudImConstant;
import com.qys.livesMall.app.user.model.entity.H2AppUser;
import com.qys.livesMall.app.user.service.IH2AppUserService;
import com.qys.livesMall.app.user.utils.TencentCloudIm;
import com.qys.livesMall.cache.RedisCache;
import com.qys.livesMall.common.result.R;
import com.qys.livesMall.common.utils.MessageUtils;
import com.qys.livesMall.finance.enums.AccountBusinessTypeEnum;
import com.qys.livesMall.finance.model.dto.FinancePayDTO;
import com.qys.livesMall.finance.service.FinanceBusinessService;
import com.qys.livesMall.finance.util.BusinessNoUtil;
import com.qys.livesMall.framework.utils.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 主播直播间表 前端控制器
 * </p>
 *
 * @author yxh
 * @since 2023-08-09
 */
@RestController
@Tag(name = "SYS-直播场次管理")
@RequestMapping("/sys/livesRoom")
@Slf4j
public class SysAnchorLivesRoomController {



    @Autowired
    private AnchorLivesRoomService livesRoomService;
    @Autowired
    private AnchorLivesSessionService livesSessionService;
    @Autowired
    private H2AnchorService anchorService;
    @Autowired
    private FinanceBusinessService financeBusinessService;
    @Autowired
    private TencentCloudIm tencentCloudIm;
    @Autowired
    private IH2AppUserService appUserService;
    @Autowired
    private AnchorSellTaskService anchorSellTaskService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private AnchorLivesBusiness anchorLivesBusiness;

    @PostMapping("/getAllRoom")
    @Operation(summary = "分页查询直播场次")
    public R<IPage<SysLiveRoomVO>> getAllRoom(@RequestBody QueryLiveRoomDTO dto) {
        return R.ok(livesSessionService.pageAllRoom(dto).convert(this::getDetail));
    }


    @GetMapping("/getDetail/{id}")
    @Operation(summary = "查询直播场次详情")
    public R<SysLiveRoomVO> getRoomDetail(@PathVariable Long id) {
        AnchorLivesSession livesSession = livesSessionService.getById(id);
        if (livesSession == null) {
            return R.ok();
        }
        return R.ok(this.getDetail(livesSession));
    }

    @PostMapping("/update")
    @Operation(summary = "修改结算数据")
    public R<?> update(@RequestBody @Validated UpdateLiveRooDTO dto) {
        AnchorLivesSession session = new AnchorLivesSession();
        session.setId(dto.getId());
        session.setViewsNumber(dto.getOnlineNumber());
        session.setSalesAmount(dto.getSalesAmount());
        session.setSalesVolume(dto.getSalesVolume());
        session.setGoldNum(dto.getGiftIncome());
        session.setOrderQuantity(dto.getOrderQuantity());
        session.setUpdateBy(SecurityUtils.getUsername());
        session.setUpdateTime(LocalDateTime.now());
        livesSessionService.updateById(session);
        return R.ok();
    }


    private SysLiveRoomVO getDetail(AnchorLivesSession livesSession) {
        //直播间信息
        AnchorLivesRoom livesRoom = livesRoomService.getById(livesSession.getLivesRoomId());
        //主播id
        Long anchorId = livesRoom.getAnchorId();
        //直播状态
        Byte livesStatus = livesSession.getLivesStatus();
        //个人信息
        H2AppUser user = livesRoomService.getUserByAnchorId(anchorId);

        SysLiveRoomVO sysLiveRoomVO = new SysLiveRoomVO();
        sysLiveRoomVO.setId(livesSession.getId());
        sysLiveRoomVO.setLiveRoomId(livesRoom.getId());
        sysLiveRoomVO.setLivesRoomName(livesSession.getLivesSessionName());
        sysLiveRoomVO.setCover(user.getAvatar());
        sysLiveRoomVO.setUserName(user.getUserName());
        sysLiveRoomVO.setNickName(user.getNickName());
        sysLiveRoomVO.setAnchorName(livesRoom.getAnchorName());
        sysLiveRoomVO.setLiveUrl(livesStatus == (byte) 2 ? getLiveUrl(anchorId) : null);
        sysLiveRoomVO.setLiveType(livesSession.getAnchorSellTaskId() == null ? 0 : 1);
        //任务计划时间（默认60）
        sysLiveRoomVO.setPlannedTime(60);
        sysLiveRoomVO.setLivesDuration(livesStatus != (byte) 2 ? livesSession.getLivesDuration() : null);
        sysLiveRoomVO.setLivesStatus(livesSession.getLivesStatus());
        sysLiveRoomVO.setUpdateTime(livesSession.getUpdateTime());
        sysLiveRoomVO.setUpdateBy(livesSession.getUpdateBy());
        sysLiveRoomVO.setRemark(livesSession.getRemark());
        if (livesStatus == (byte) 3) {
            sysLiveRoomVO.setOnlineNumber(livesSession.getViewsNumber());
            sysLiveRoomVO.setSalesAmount(livesSession.getSalesAmount());
            sysLiveRoomVO.setSalesVolume(livesSession.getSalesVolume());
            sysLiveRoomVO.setOrderQuantity(livesSession.getOrderQuantity());
            sysLiveRoomVO.setGiftIncome(livesSession.getGoldNum());
            sysLiveRoomVO.setPlatformSettlement(livesSession.getPlatformSettlement());
        }
        //切流状态
        sysLiveRoomVO.setStreamState(StringUtils.isNotBlank(livesSession.getSourceType()) ? "1" : "0");
        String autoPushAddress = livesSession.getAutoPushAddress();
        sysLiveRoomVO.setStreamUrl(StringUtils.isBlank(autoPushAddress) ? Lists.newArrayList() : List.of(autoPushAddress.split(",")));
        return sysLiveRoomVO;
    }


    /**
     * 将rtmp协议的流转换成webrtc协议，用于web播放
     *
     * @param anchorId
     * @return
     */
    private String getLiveUrl(Long anchorId) {
        String id = livesRoomService.getUserByAnchorId(anchorId).getId();
        String playUrl = LiveStreamUtils.getPlayUrl(Long.valueOf(id));
        return playUrl.replace("rtmp", "webrtc");
    }

    @PostMapping("/platformSettlement/{id}")
    @Operation(summary = "平台结算")
    @Transactional(rollbackFor = Exception.class)
    public R<?> platformSettlement(@PathVariable Long id) {
        AnchorLivesSession livesSession = livesSessionService.getById(id);
        if (livesSession == null || livesSession.getLivesStatus() != (byte) 3 || livesSession.getPlatformSettlement() != 0) {
            return R.fail();
        }

        H2Anchor anchor = anchorService.getById(livesSession.getAnchorId());
        //直播时长
        Integer livesDuration = livesSession.getLivesDuration();
        //结算方式
        Integer clearingForm = anchor.getClearingForm();
        if (null == clearingForm) {
            return R.fail(MessageUtils.message("no.billing.method.is.set"));
        }
        //底薪
        String basicSalary = anchor.getBasicSalary();
        //礼物比例
        BigDecimal giftRatio = anchor.getGiftRatio() == null ? BigDecimal.ZERO : anchor.getGiftRatio();

        if (1 == clearingForm || 3 == clearingForm) {
            //底薪是否配置
            if (StringUtils.isEmpty(basicSalary)) {
                return R.fail(MessageUtils.message("no.base.salary.allocation"));
            }
            //底薪结算
            BigDecimal amountIncurred = getValueBasedOnTime(livesDuration, basicSalary);
            if(amountIncurred.compareTo(BigDecimal.ZERO) > 0){
                //当底薪大于0再进行结算底薪
                FinancePayDTO financePayDTO = new FinancePayDTO();
                financePayDTO.setUserId(anchor.getUserId());
                financePayDTO.setBusinessType(AccountBusinessTypeEnum.LIVES_BASIC_SALARY);
                financePayDTO.setAmountIncurred(amountIncurred);
                financePayDTO.setBusinessNo(BusinessNoUtil.get(AccountBusinessTypeEnum.LIVES_BASIC_SALARY));
                financeBusinessService.pay(financePayDTO);
                if (!financePayDTO.getSuccess()) {
                    return R.fail(financePayDTO.getMessage());
                }
            }
        }

        BigDecimal decimal = livesSession.getGoldNum().multiply(giftRatio);
        if(decimal.compareTo(BigDecimal.ZERO) != 0){
            //礼物结算
            FinancePayDTO financePayDTO = new FinancePayDTO();
            financePayDTO.setUserId(anchor.getUserId());
            financePayDTO.setBusinessType(AccountBusinessTypeEnum.LIVES_GIFT_GET);
            financePayDTO.setAmountIncurred(decimal);
            financePayDTO.setBusinessNo(BusinessNoUtil.get(AccountBusinessTypeEnum.LIVES_GIFT_GET));
            financeBusinessService.pay(financePayDTO);
            if (!financePayDTO.getSuccess()) {
                return R.fail(financePayDTO.getMessage());
            }
        }

        livesSession.setPlatformSettlement(1);
        livesSessionService.updateById(livesSession);

        //更新主播带货任务状态
        AnchorSellTask anchorSellTask = new AnchorSellTask();
        anchorSellTask.setId(livesSession.getAnchorSellTaskId());
        anchorSellTask.setStatus((byte)3);
        anchorSellTaskService.updateById(anchorSellTask);
        return R.ok();
    }


    @PostMapping("/nonStandardSettlement/{id}")
    @Operation(summary = "未达标平台结算")
    @Transactional(rollbackFor = Exception.class)
    public R<?> nonStandardSettlement(@PathVariable Long id, @RequestBody Map<String,String> map){
        AnchorLivesSession livesSession = livesSessionService.getById(id);
        if (livesSession == null || livesSession.getLivesStatus() != (byte) 3 || livesSession.getPlatformSettlement() != 0) {
            return R.fail();
        }
        livesSession.setPlatformSettlement(2);
        livesSession.setRemark(map.get("remark"));
        livesSessionService.updateById(livesSession);

        //更新主播带货任务状态
        AnchorSellTask anchorSellTask = new AnchorSellTask();
        anchorSellTask.setId(livesSession.getAnchorSellTaskId());
        anchorSellTask.setStatus((byte)3);
        anchorSellTaskService.updateById(anchorSellTask);
        return R.ok();
    }

    /**
     * 根据直播时长匹配底薪
     * @param livesDuration  直播时长
     * @param basicSalary  底薪配置
     * @return
     */
    private BigDecimal getValueBasedOnTime(Integer livesDuration, String basicSalary) {
        JSONObject jsonObject = JSONObject.parseObject(basicSalary);

        BigDecimal result = BigDecimal.ZERO;
        for (String key : jsonObject.keySet()) {
            if (Integer.parseInt(key) <= livesDuration) {
                String val = (String) jsonObject.get(key);
                result =  new BigDecimal(val);
            }
        }

        return result;
    }

    /**
     * 根据地址解析流
     * @param address url地址
     * @return 流地址
     */
    @GetMapping("/resolutionAddress")
    @Operation(summary = "解析地址")
    public R<?> resolutionAddress(@RequestParam String address) {
        String res = null;
        try {
            Map<String, Object> map = Maps.newHashMap();
            map.put("url", address);
            res = HttpUtil.post("http://localhost:7123/parse", JSONObject.toJSONString(map));
            JSONObject jsonObject = JSONObject.parseObject(res);
            res = (String) jsonObject.get("result");
        } catch (Exception e) {
            return R.fail("解析失败，{}", res);
        }
        return R.ok(res);
    }



    @PostMapping("/enableAutomaticLive/{sessionId}")
    @Operation(summary = "开启/关闭自动直播")
    public R<?> enableAutomaticLive(@PathVariable Long sessionId, @RequestBody CreatePullFlowDTO dto) {
        AnchorLivesSession session = livesSessionService.getById(sessionId);
        if(session == null){
            return R.fail(MessageUtils.message("直播间场次不存在"));
        }
        String userId = livesRoomService.getUserByAnchorId(session.getAnchorId()).getId();

        String taskId = redisCache.getCacheObject(RedisConstant.AUTOMATIC_LIVE + userId);
        if(StringUtils.isNotEmpty(taskId)){
            //删除拉流任务
            LiveStreamUtils.exampleDeleteAPullTask(taskId);
            redisCache.deleteObject(RedisConstant.AUTOMATIC_LIVE + userId);
            //更新场次表
            session.setSourceType(StringUtils.EMPTY);
            session.setAutoPushAddress(StringUtils.EMPTY);
            livesSessionService.updateById(session);
            return R.ok();
        }

        try {
            dto.setStartTime(dto.getStartTime() == null ? System.currentTimeMillis() : dto.getStartTime());
            dto.setEndTime(dto.getEndTime() == null ? System.currentTimeMillis() + 8000 * 60 * 60 : dto.getEndTime());
            dto.setStreamName(userId);
            taskId = LiveStreamUtils.createPullFlow(dto);
            if(StringUtils.isNotEmpty(taskId)){
                redisCache.setCacheObject(RedisConstant.AUTOMATIC_LIVE + userId, taskId, 60L, TimeUnit.MINUTES);
            } else {
                return R.fail(MessageUtils.message("error.parameter"));
            }
        } catch (Exception e) {
            log.error("创建拉流转推任务失败:{}", e.getMessage());
            return R.fail(MessageUtils.message("error.parameter"));
        }

        //在创建拉流转推任务后延迟3秒切备用流
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(1);
        threadPool.schedule(()-> LiveStreamUtils.switchBackupStream(userId), 1, TimeUnit.SECONDS);
        threadPool.shutdown();

        //更新直播场次推流信息
        session.setSourceType(dto.getSourceType());
        session.setAutoPushAddress(String.join(",", dto.getSourceUrls()));
        livesSessionService.updateById(session);
        return R.ok();
    }


    @PostMapping("/closeLive/{sessionId}")
    @Operation(summary = "后台强制关闭直播间")
    public R<?> closeLive(@PathVariable Long sessionId) {
        AnchorLivesSession livesSession = livesSessionService.getById(sessionId);
        if (livesSession == null || livesSession.getLivesStatus() != (byte) 2) {
            return R.ok();
        }
        H2Anchor anchor = anchorService.getById(livesSession.getAnchorId());
        anchorLivesBusiness.closeLive(anchor.getUserId(), true, null);
        return R.ok();
    }

    @PostMapping("/sendMessage")
    @Operation(summary = "水军发送弹幕消息")
    public R<?> sendMessage(@RequestBody SendMessageDTO dto) {
        //根据场次id获取直播间编号
        AnchorLivesRoom livesRoom = livesRoomService.getById(dto.getLiveRoomId());
        if(livesRoom == null || livesRoom.getLiveStatus() != (byte)2){
            return R.fail("room no living");
        }
        if (CollectionUtils.isNotEmpty(dto.getUserId())) {
            for (String id : dto.getUserId()) {
                List<String> userId = Lists.newArrayList(id);
                //先检查用户是否导入IM
                Map<String, Boolean> resultMap = tencentCloudIm.accountCheck(userId);
                Boolean flag = resultMap.get(id);
                //如果没有导入IM  则重新导入
                if (!flag) {
                    H2AppUser h2AppUser = appUserService.getById(id);
                    tencentCloudIm.accountImport(id, h2AppUser.getNickName(), h2AppUser.getAvatar());
                }
                //再检查用户是否在群里(默认直播群已经创建)
                String resultStatus = tencentCloudIm.checkUserInGroup(livesRoom.getLivesRoomNum(), userId);
                if (StringUtils.equalsIgnoreCase(TencentCloudImConstant.ACTION_STATUS_FAIL, resultStatus)) {
                    tencentCloudIm.addGroupMember(livesRoom.getLivesRoomNum(), userId);
                }

                String message = livesSessionService.randomMessage(0);
                tencentCloudIm.sendMsg(id, livesRoom.getLivesRoomNum(), TencentCloudImConstant.TIM_TEXT_ELEM, message);
            }
        }
        return R.ok();
    }
}
